package com.example.service;

import com.example.entity.Block;
import com.example.entity.Transaction;
import com.example.entity.Event;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameterNumber;
import org.web3j.protocol.core.methods.response.EthBlock;
import org.web3j.protocol.core.methods.response.Log;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import jakarta.annotation.Resource;
import java.math.BigInteger;
import java.util.List;

/**
 * 区块链批量同步与监听服务
 */
@Service
public class BlockSyncService {

    @Value("${web3j.sync.start-block-number:0}")
    private Long startBlockNumberConfig;
    /**
     * 配置文件注入的合约地址
     */
    @Value("${web3j.contract.token-address}")
    private String contractAddress;

    /**
     * 服务启动后自动监听区块和合约交易/事件
     */
    @jakarta.annotation.PostConstruct
    public void autoStartSync() {
        try {
            // 可扩展为多合约监听，当前单合约
            syncBlocks(contractAddress);
        } catch (Exception e) {
            // 建议完善日志
            System.err.println("[BlockSyncService] 自动监听启动失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    @Value("${web3j.sync.block-step:10000}")
    private Integer syncBlockStep;

    @Resource
    private Web3j web3j;

    @Resource
    private BlockService blockService;

    @Resource
    private TransactionService transactionService;

    @Resource
    private EventService eventService;

    /**
     * 批量同步区块（每批10000个区块）
     * @param contractAddress 只处理该合约相关交易和事件
     */
    public void syncBlocks(String contractAddress) throws Exception {
        Long lastBlock = blockService.getLatestBlockNumber();
        Long startBlock = 0L;
        if (startBlockNumberConfig != null && startBlockNumberConfig > 0) {
            startBlock = startBlockNumberConfig;
        }
        if (lastBlock == null || lastBlock < startBlock) {
            lastBlock = startBlock - 1;
        }
        BigInteger latest = web3j.ethBlockNumber().send().getBlockNumber();
        for (long start = lastBlock + 1; start <= latest.longValue(); start += syncBlockStep) {
            long end = Math.min(start + syncBlockStep - 1, latest.longValue());
            for (long i = start; i <= end; i++) {
                EthBlock.Block block = web3j.ethGetBlockByNumber(new DefaultBlockParameterNumber(i), true).send().getBlock();
                if (block == null) continue;

                // 入库区块
                Block dbBlock = new Block();
                dbBlock.setBlockNumber(Long.valueOf(block.getNumber().longValue()));
                dbBlock.setBlockHash(block.getHash());
                dbBlock.setParentBlockHash(block.getParentHash());
                blockService.saveBlock(dbBlock);

                // 区块时间戳（秒）转Date
                java.util.Date txTime = new java.util.Date(block.getTimestamp().longValue() * 1000);

                // 处理交易
                block.getTransactions().forEach(txObj -> {
                    EthBlock.TransactionObject tx = (EthBlock.TransactionObject) txObj.get();
                    if (contractAddress.equalsIgnoreCase(tx.getTo())) {
                        Transaction dbTx = new Transaction();
                        dbTx.setTxHash(tx.getHash());
                        dbTx.setFromAddress(tx.getFrom());
                        dbTx.setToAddress(tx.getTo());
                        dbTx.setValue(new java.math.BigDecimal(tx.getValue()));
                        dbTx.setContractAddress(tx.getTo());
                        dbTx.setBlockNumber(Long.valueOf(block.getNumber().longValue()));
                        dbTx.setGasPrice(Long.valueOf(tx.getGasPrice().longValue()));
                        dbTx.setStatus(Integer.valueOf(1)); // 默认成功，后续可查Receipt
                        dbTx.setTxTime(txTime);
                        dbTx.setRawTx(com.alibaba.fastjson2.JSON.toJSONString(tx));
                        transactionService.saveTransaction(dbTx);
                    }
                });

                // 并发处理事件（每个区块内的交易并发处理）
                block.getTransactions().parallelStream().forEach(txObj -> {
                    EthBlock.TransactionObject tx = (EthBlock.TransactionObject) txObj.get();
                    if (contractAddress.equalsIgnoreCase(tx.getTo())) {
                        try {
                            TransactionReceipt receipt = web3j.ethGetTransactionReceipt(tx.getHash()).send().getTransactionReceipt().orElse(null);
                            if (receipt != null) {
                                List<Log> logs = receipt.getLogs();
                                for (Log log : logs) {
                                    if (contractAddress.equalsIgnoreCase(log.getAddress())) {
                                        Event dbEvent = new Event();
                                        dbEvent.setTxHash(tx.getHash());
                                        dbEvent.setBlockNumber(Long.valueOf(block.getNumber().longValue()));
                                        dbEvent.setContractAddress(log.getAddress());
                                        dbEvent.setEventData(com.alibaba.fastjson2.JSON.toJSONString(log));
                                        dbEvent.setLogIndex(Integer.valueOf(log.getLogIndex().intValue()));
                                        eventService.saveEvent(dbEvent);
                                    }
                                }
                            }
                        } catch (Exception ignore) {}
                    }
                });
            }
        }
    }
}
